package auth

import (
	"errors"
	"fmt"
	"strings"

	"github.com/gin-gonic/gin"
	"github.com/golang-jwt/jwt/v4"
	"github.com/wzh200x/hyperNexus/hyperNexusProtocol/cacheServerProtocol"
	"github.com/wzh200x/webServer/constants"
	"github.com/wzh200x/webServer/middleware/response"
	Server "github.com/wzh200x/webServer/server"
)

// JWT密钥
var jwtSecret = []byte("webServer_secret_key")

// JWT声明结构
type Claims struct {
	UserID    uint   `json:"user_id"`
	Username  string `json:"username"`
	LoginUUID string `json:"login_uuid"` // 添加登录UUID字段，用于多端登录控制
	jwt.RegisteredClaims
}

// 解析和验证JWT令牌
func ParseToken(token string) (*Claims, error) {
	tokenClaims, err := jwt.ParseWithClaims(token, &Claims{}, func(token *jwt.Token) (interface{}, error) {
		return jwtSecret, nil
	})

	if err != nil {
		return nil, err
	}

	if tokenClaims != nil {
		if claims, ok := tokenClaims.Claims.(*Claims); ok && tokenClaims.Valid {
			return claims, nil
		}
	}

	return nil, errors.New("invalid token")
}

// JWTAuth JWT鉴权中间件
func JWTAuth() gin.HandlerFunc {
	return func(c *gin.Context) {
		// 获取Authorization头
		authorization := c.GetHeader("Authorization")
		if authorization == "" {
			response.Error(c, constants.ErrAuthToken, "请求未携带令牌")
			c.Abort()
			return
		}

		// 检查Bearer前缀
		parts := strings.SplitN(authorization, " ", 2)
		if !(len(parts) == 2 && parts[0] == "Bearer") {
			response.Error(c, constants.ErrAuthToken, "令牌格式错误")
			c.Abort()
			return
		}

		// 解析令牌
		claims, err := ParseToken(parts[1])
		if err != nil {
			response.Error(c, constants.ErrAuthCheckTokenFail, "令牌无效: "+err.Error())
			c.Abort()
			return
		}

		// 验证登录UUID是否在缓存中有效
		if claims.LoginUUID != "" {
			cacheClient := Server.ServerApp.CacheServerClient.GetClientProxy()
			cacheKey := fmt.Sprintf("auth:%s:%d", claims.Username, claims.UserID)

			// 从缓存中获取登录信息
			cacheGetReq := cacheServerProtocol.CacheGetRequest{
				Key: cacheKey,
			}

			cacheResp, err := cacheClient.Get(cacheGetReq)
			if err != nil || !cacheResp.Exists {
				// 缓存中不存在该UUID，可能是已在其他设备登录或令牌已失效
				response.Error(c, constants.ErrAuthToken, "登录已失效，请重新登录")
				c.Abort()
				return
			}
			// 验证登录UUID是否匹配
			if claims.LoginUUID != string(cacheResp.Value) {
				response.Error(c, constants.ErrAuthToken, "登录已失效，请重新登录")
				c.Abort()
				return
			}
		}

		// 将用户信息存储到上下文中
		c.Set("claims", claims)
		c.Set("userID", claims.UserID)
		c.Set("username", claims.Username)
		c.Set("loginUUID", claims.LoginUUID)

		c.Next()
	}
}

// GetCurrentUser 从上下文中获取当前用户信息
func GetCurrentUser(c *gin.Context) (userID uint, username string) {
	userIDInterface, _ := c.Get("userID")
	userID = userIDInterface.(uint)
	usernameInterface, _ := c.Get("username")
	username = usernameInterface.(string)
	return userID, username
}
